package org.java.xianxin.aspect;

import cn.hutool.core.lang.UUID;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.java.xianxin.annotation.LogAnnotation;
import org.java.xianxin.entity.LogEntity;
import org.java.xianxin.service.LogExceptionService;
import org.java.xianxin.service.LogSaveService;
import org.java.xianxin.util.StringUtils;
import org.java.xianxin.web.Response;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;


/**
 * <p>
 * 打印日志切面
 * </p>
 *
 * @author 敖燕飞
 * @since 下午6:02 2019/8/26
 */
@Aspect
@Order(-1)
@Slf4j
@Component
public class LogAnnotationAspect {

    @Autowired
    private LogSaveService<LogEntity> logSaveService;

    @Autowired
    private LogExceptionService logExceptionService;

    @Around("@annotation(logAnnotation)")
    public Object print(ProceedingJoinPoint joinPoint, LogAnnotation logAnnotation) throws Throwable {
        StopWatch watch = new StopWatch();
        watch.start();

        LogEntity logEntity = new LogEntity();

        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert attributes != null;
        HttpServletRequest request = attributes.getRequest();
        String logId = request.getHeader("X-B3-TraceId");
        if (StringUtils.isEmpty(logId)) {
            logId = UUID.fastUUID().toString().replaceAll("-", "");
            MDC.put("X-B3-TraceId", logId);
        }
        logEntity.setLogId(logId);

        String methodName = joinPoint.getSignature().getName();
        logEntity.setMethodName(methodName);

        //包路径
        //String packagePath = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();

        Object result = null;
        List<Object> httpReqArgs = new ArrayList<>();

        try {
            log.info("访问者IP:{} 行为:{}-{}", request.getRemoteAddr(), logAnnotation.module(), logAnnotation.business());
            logEntity.setModule(logAnnotation.module());
            logEntity.setBusiness(logAnnotation.business());

            //记录下请求内容
            String reqUrl = request.getRequestURL().toString();
            log.info("接口地址:{}", reqUrl);
            logEntity.setReqUrl(reqUrl);

            //log.info("包路径：{}", packagePath);

            //参数值
            Object[] args = joinPoint.getArgs();
            logEntity.setReqArgs(args);

            for (Object object : args) {
                if (object instanceof HttpServletRequest) {

                } else if (object instanceof HttpServletResponse) {

                } else {
                    httpReqArgs.add(object);
                }
            }

            try {
                String params = JSONObject.toJSONString(httpReqArgs);
                // 打印请求参数参数
                log.info("接口:[{}-{}] - 请求参数:{} ", methodName, request.getMethod(), params);
            } catch (Exception e) {
                log.error("接口:[{}-{}] - 记录参数失败:{}", methodName, request.getMethod(), e.getMessage());
            }

            logEntity.setReqMethod(request.getMethod());

            result = joinPoint.proceed();

            if (result instanceof Response) {
                Response response = (Response) result;
                logEntity.setCode(response.getCode());
                logEntity.setMsg(response.getMsg());
            }
        } catch (Exception e) {
            //throw e;
            Response<Object> response = logExceptionService.handle(e);
            if (response != null) {
                logEntity.setCode(response.getCode());
                logEntity.setMsg(response.getMsg());
            } else {
                logEntity.setCode(555);
                logEntity.setMsg("失败");
            }
            result = response;
        } finally {
            watch.stop();
            double time = watch.getTotalTimeSeconds();

            //获取回执报文及耗时
            String respParameter = JSON.toJSONString(result);
            log.info("接口:[{}-{}] - 耗时:{}s - 响应参数:{}", methodName, request.getMethod(), time, respParameter);
            logEntity.setRespArgs(respParameter);
            logEntity.setTime(time);

            //是否存储日志
            if (logAnnotation.recordRequestParam()) {
                logSaveService.save(logEntity);
            }
        }

        return result;
    }
}
